package ua.net.gm.server.walker;

import ua.net.gm.server.condition.ICondition;
import ua.net.gm.server.primitives.Point;
import ua.net.gm.server.primitives.Rectangle;

/**
 *
 * @author Yason
 */
public class Walker implements IWalker
{
    /**
     * walker available to move area
     */
    private final Rectangle area;    
    /**
     * walker starting point
     */
    private final Point startPosition;
    /**
     * current position
     */
    private Point position;
    /**
     * successful move count
     */
    private int stepCounter = 0;
    /**
     * unsuccessful move count
     */
    private int failMoveCounter = 0;
    /**
     * last unsuccessful moves attempts at a stretch
     */
    private int lastFailStreakCounter = 0;
    /**
     * previous position coordinate
     */
    private Point lastPosition = null;    
    /**
     * last successful move type
     */
    private IWalkerMove lastMove = null;
    /**
     * last unsuccessful move type
     */
    private IWalkerMove lastFailMove = null;
    /**
     * was last move unsuccessful
     */
    private boolean lastMoveFail = false;
    /**
     * does it finished to walk
     */
    private boolean stopped = false;
    /**
     * moving strategy
     */
    private final IWalkerStrategy strategy;
    /**
     * to check is it possible to make move suggest by strategy
     */
    private final ICondition moveCondition;
    /**
     * to check is walkers way over
     */
    private final ICondition stopCondition;
    
    @Override
    public Rectangle getArea()
    {
        return area;
    }
    
    public Walker(Rectangle area, Point position, IWalkerStrategy strategy, 
            ICondition moveCondition, ICondition stopCondition)
    {
        this.area = area;
        this.startPosition = position;
        this.position = position;
        this.strategy = strategy;
        this.stopCondition = stopCondition;
        this.moveCondition = moveCondition;
    }

    @Override
    public Point getStartPosition()
    {
        return startPosition;
    }
    
    @Override
    public Point getPosition()
    {
        return position;
    }
    
    @Override
    public int getStepCount()
    {
        return stepCounter;
    }

    @Override
    public int getFailCount()
    {
        return failMoveCounter;
    }

    @Override
    public IWalkerMove getLastMove()
    {
        return lastMove;
    }

    @Override
    public IWalkerMove getLastFailMove()
    {
        return lastFailMove;
    }

    @Override
    public boolean isLastMoveFail()
    {
        return lastMoveFail;
    }

    @Override
    public int getLastFailStreakCount()
    {
        return lastFailStreakCounter;
    }

    @Override
    public boolean isStopped()
    {
        return stopped;
    }

    @Override
    public Point getLastPosition()
    {
        return lastPosition;
    }
    
    @Override
    public void walk()
    {
        if (!isStopped())
        {
            stepCounter++;
            
            IWalkerMove move = strategy.getMove(this);
            
            if (move != null && moveCondition.permit(new WalkerMoveConditionContext(this, move)))
            {
                lastPosition = position;
                position = move.getNextPosition(this);
                lastMove = move;
                lastFailStreakCounter = 0;
                lastMoveFail = false;
            }
            else
            {
                lastMoveFail = true;
                lastFailStreakCounter++;
                failMoveCounter++;
                lastFailMove = move;
            }
            
            if (stopCondition.permit(new WalkerConditionContext(this)))
            {
                stopped = true;
            }
        }
    }
}